package com.zzyl.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import com.google.common.collect.Lists;
import com.zzyl.constant.CacheConstant;
import com.zzyl.constant.SuperConstant;
import com.zzyl.dto.ResourceDto;
import com.zzyl.entity.Resource;
import com.zzyl.enums.BasicEnum;
import com.zzyl.exception.BaseException;
import com.zzyl.mapper.ResourceMapper;
import com.zzyl.mapper.RoleResourceMapper;
import com.zzyl.service.ResourceService;
import com.zzyl.service.RoleService;
import com.zzyl.utils.EmptyUtil;
import com.zzyl.utils.NoProcessing;
import com.zzyl.utils.StringUtils;
import com.zzyl.utils.UserThreadLocal;
import com.zzyl.vo.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.cache.annotation.Caching;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.stream.Collectors;

@Service
public class ResourceServiceImpl implements ResourceService {

    @Autowired
    private ResourceMapper resourceMapper;
    @Autowired
    RoleResourceMapper roleResourceMapper;
    @Autowired
    RoleService roleService;


    /**
     * 多条件查询资源列表
     *
     * @param resourceDto
     * @return
     */

    @Cacheable(value = CacheConstant.RESOURCE_LIST, key = "#resourceDto.hashCode()")
    @Override
    public List<ResourceVo> findResourceList(ResourceDto resourceDto) {
        List<Resource> resourceList = resourceMapper.selectList(resourceDto);
        return BeanUtil.copyToList(resourceList, ResourceVo.class);
    }

    /**
     * 树形结构
     *
     * @param resourceDto
     * @return
     */
    @Override
    @Cacheable(value = CacheConstant.RESOURCE_TREE)
    public TreeVo resourceTreeVo(ResourceDto resourceDto) {
        //构造查询条件
        ResourceDto dto = ResourceDto.builder()
                .dataState(SuperConstant.DATA_STATE_0)
                .parentResourceNo(NoProcessing.processString(SuperConstant.ROOT_PARENT_ID))
                .resourceType(SuperConstant.MENU).build();
        //查询所有资源数据
        List<Resource> resourceList = resourceMapper.selectList(dto);
        if (EmptyUtil.isNullOrEmpty(resourceList)) {
            throw new RuntimeException("资源信息未定义");
        }
        //没有根节点，构建根节点
        Resource rootResource = new Resource();
        rootResource.setResourceNo(SuperConstant.ROOT_PARENT_ID);
        rootResource.setResourceName("智慧养老院");

        //返回的树形集合
        List<TreeItemVo> itemVos = new ArrayList<>();

        //使用递归构建树形结构
        recursionTreeItem(itemVos, rootResource, resourceList);

        return TreeVo.builder().items(itemVos).build();
    }


    /**
     * 使用递归构建树形结构
     *
     * @param itemVos
     * @param rootResource
     * @param resourceList
     */
    private void recursionTreeItem(List<TreeItemVo> itemVos, Resource rootResource, List<Resource> resourceList) {
        //构建每个资源的属性
        TreeItemVo treeItemVo = TreeItemVo.builder()
                .id(rootResource.getResourceNo())
                .label(rootResource.getResourceName()).build();
        //获取当前资源下的子资源
        List<Resource> childrenResourceList = resourceList.stream()
                .filter(n -> n.getParentResourceNo().equals(rootResource.getResourceNo()))
                .collect(Collectors.toList());
        //判断子资源是否为空
        if (!EmptyUtil.isNullOrEmpty(childrenResourceList)) {
            List<TreeItemVo> listChildren = new ArrayList<>();
            //构建子资源
            childrenResourceList.forEach(resource -> {
                recursionTreeItem(listChildren, resource, resourceList);
            });
            treeItemVo.setChildren(listChildren);
        }

        //添加到集合
        itemVos.add(treeItemVo);

    }

    /**
     * 添加资源
     *
     * @param resourceDto
     */
    @Override
    @Caching(evict = {
            @CacheEvict(value = CacheConstant.RESOURCE_LIST, allEntries = true),
            @CacheEvict(value = CacheConstant.RESOURCE_TREE, allEntries = true)
    })
    public void createResource(ResourceDto resourceDto) {
        //属性拷贝
        Resource resource = BeanUtil.toBean(resourceDto, Resource.class);
        //查询父资源
        Resource parentResource = resourceMapper.selectByResourceNo(resourceDto.getParentResourceNo());
        resource.setDataState(parentResource.getDataState());
        boolean isIgnore = true;
        //判断是否是按钮，如果是按钮，则不限制层级
        if (StringUtils.isNotEmpty(resourceDto.getResourceType())
                && resourceDto.getResourceType().equals(SuperConstant.BUTTON)) {
            isIgnore = false;
        }
        //创建当前资源的编号
        String resourceNo = createResourceNo(resourceDto.getParentResourceNo(), isIgnore);
        resource.setResourceNo(resourceNo);
        resourceMapper.insert(resource);

    }

    @Override
    @Caching(evict = {
            @CacheEvict(value = CacheConstant.RESOURCE_LIST, allEntries = true),
            @CacheEvict(value = CacheConstant.RESOURCE_TREE, allEntries = true)
    })
    public Boolean updateResource(ResourceDto resourceDto) {
        Resource resource = BeanUtil.toBean(resourceDto, Resource.class);
        if (resource.getDataState().equals("1")) {
            if (hasChildByMenuId(resource.getResourceNo())) {
                throw new RuntimeException("存在子菜单,不允许禁用");
            }
            if (checkMenuExistRole(resource.getResourceNo())) {
                throw new RuntimeException("菜单已分配,不允许禁用");
            }
        }
        int flag = resourceMapper.updateByPrimaryKeySelective(resource);
        if (flag == 0) {
            throw new RuntimeException("修改资源信息出错");
        }
        return true;
    }

    @Override
    @Caching(evict = {
            @CacheEvict(value = CacheConstant.RESOURCE_LIST, allEntries = true),
            @CacheEvict(value = CacheConstant.RESOURCE_TREE, allEntries = true)
    })
    public Boolean isEnable(ResourceDto resourceDto) {
        //1.启用部门
        if (resourceDto.getDataState().equals("0")) {
            //1.1 判断父级菜单是否是禁用，如果是禁用，不允许启用
            String parentResourceNo = resourceDto.getParentResourceNo();
            Resource resource = resourceMapper.selectByResourceNo(parentResourceNo);
            if (resource != null && resource.getDataState().equals("1")) {
                throw new BaseException(BasicEnum.PARENT_MENU_DISABLE);
            }
        }
        Resource resource = BeanUtil.toBean(resourceDto, Resource.class);
        //检验是否可以修改
        if (resource.getDataState().equals("1")) {
            if (checkMenuExistRole(resource.getResourceNo())) {
                throw new RuntimeException("菜单关联着角色,不允许禁用");
            }
        }

        //判断是否有子菜单，如果有子菜单，则一起启用或禁用
        String resourceNo = resourceDto.getResourceNo();
        resourceMapper.updateByResourceNo(resourceNo, resourceDto.getDataState());
        resourceMapper.updateByParentResourceNo(NoProcessing.processString(resourceNo), resourceDto.getDataState());
        return true;
    }

    @Override
    @Caching(evict = {
            @CacheEvict(value = CacheConstant.RESOURCE_LIST, allEntries = true),
            @CacheEvict(value = CacheConstant.RESOURCE_TREE, allEntries = true)
    })
    public int deleteResourceNo(String resourceNo) {
        if (resourceMapper.selectByResourceNo(resourceNo).getDataState().equals("0")) {
            throw new RuntimeException("菜单启用中不允许删除");
        }
        if (hasChildByMenuId(resourceNo)) {
            throw new RuntimeException("存在子菜单,不允许删除");
        }
        if (checkMenuExistRole(resourceNo)) {
            throw new RuntimeException("菜单已分配,不允许删除");
        }

        return resourceMapper.deleteMenuById(resourceNo);
    }

    /**
     * 动态菜单
     * @param userId
     * @return
     */
    @Override
    public List<MenuVo> menus(Long userId) {
        //查询用户对应的所有菜单数据
        List<MenuVo> menuVoList = resourceMapper.findListByUserId(userId);
        if(CollUtil.isEmpty(menuVoList)){
            throw new BaseException(BasicEnum.USER_ROLE_AND_MENU_EMPTY);
        }
        //数据进行分组
        Map<String, List<MenuVo>> parentRNoMap = menuVoList
                .stream()
                .collect(Collectors.groupingBy(MenuVo::getParentResourceNo));
        //遍历所有数据
        menuVoList.forEach(menuVo -> {
            menuVo.setMeta(MenuMetaVo.builder().title(menuVo.getName()).build());
            menuVo.setRedirect("/" + menuVo.getName());
            //根据父编号到map集合中找是否包含子菜单，如果包含设置为当前菜单的子菜单
            List<MenuVo> menuVos = parentRNoMap.get(menuVo.getResourceNo());
            if(!EmptyUtil.isNullOrEmpty(menuVos)){
                menuVos.forEach(m -> {
                    m.setMeta(MenuMetaVo.builder().title(m.getName()).build());
                    m.setRedirect("/" + m.getName());
                });
                menuVo.setChildren(menuVos);
            }
        });
        //根据根编号查询所有的子
        return parentRNoMap.get(SuperConstant.ROOT_PARENT_ID);
    }

    /**
     * 查询当前登录人的按钮
     *
     * @return
     */
    @Override
    public List<MenuVo> buttons() {
        Long mgtUserId = UserThreadLocal.getMgtUserId();
        //查询对应角色
        List<RoleVo> roleVoList = roleService.findRoleVoListInUserId(Arrays.asList(mgtUserId));
        List<Long> roleIds = roleVoList.stream().map(RoleVo::getId).collect(Collectors.toList());
        if (CollUtil.isEmpty(roleIds)) {
            throw new BaseException(BasicEnum.ASSIGN_ROLE_MEAN);
        }
        //全部的菜单，包含了菜单和按钮
        List<ResourceVo> resources = resourceMapper.findButtonVoListInRoleId(roleIds);

        List<MenuVo> list = new ArrayList<>();
        recursionButtonVo(list, resources);
        return list;
    }

    /**
     * 递归按钮
     */
    public List<MenuVo> recursionButtonVo(List<MenuVo> list, List<ResourceVo> resources) {
        for (ResourceVo resource : resources) {
            if (resource.getParentResourceNo().equals(SuperConstant.ROOT_PARENT_ID)) {
                MenuVo menuVo = new MenuVo();
                menuVo.setPath(resource.getRequestPath());
                menuVo.setName(resource.getResourceName());
                menuVo.setChildren(getAllChildrens(resource, resources));
                list.add(menuVo);
            }
        }
        return list;
    }


//    /**
//     * 递归按钮
//     */
//    public List<MenuVo> recursionMenuVo(List<MenuVo> list, List<ResourceVo> resources) {
//        for (ResourceVo resource : resources) {
//            if (resource.getParentResourceNo().equals(SuperConstant.ROOT_PARENT_ID)) {
//                MenuVo menuVo = new MenuVo();
//                menuVo.setPath(resource.getRequestPath());
//                menuVo.setName(resource.getResourceName());
//                menuVo.setPath("/" + resource.getRequestPath());
//                menuVo.setComponent(SuperConstant.COMPONENT_LAYOUT);
//
//                MenuMetaVo menuMetaVo = MenuMetaVo.builder()
//                        .icon(resource.getIcon())
//                        .title(resource.getResourceName())
//                        .build();
//                menuVo.setMeta(menuMetaVo);
//                menuVo.setRedirect("/" + resource.getResourceName());
//
//                menuVo.setChildren(getChildrens(resource, resources, resource.getRequestPath()));
//                list.add(menuVo);
//            }
//        }
//        return list;
//    }

    /**
     * 递归获取菜单和按钮
     *
     * @param resource
     * @param resources
     * @return
     */
    private List<MenuVo> getAllChildrens(ResourceVo resource, List<ResourceVo> resources) {

        List<MenuVo> childrenList = Lists.newArrayList();
        for (ResourceVo resourceVo : resources) {
            if (resourceVo.getParentResourceNo().equals(resource.getResourceNo())) {
                MenuVo menuVo = new MenuVo();
                menuVo.setPath(resourceVo.getRequestPath());
                menuVo.setName(resourceVo.getResourceName());
                menuVo.setChildren(getAllChildrens(resourceVo, resources));
                childrenList.add(menuVo);
            }
        }

        return childrenList;
    }
//
//    /**
//     * 递归获取菜单和按钮
//     *
//     * @param resource
//     * @param resources
//     * @return
//     */
//    private List<MenuVo> getChildrens(ResourceVo resource, List<ResourceVo> resources, String component) {
//
//        List<MenuVo> childrenList = Lists.newArrayList();
//        for (ResourceVo resourceVo : resources) {
//            if (resourceVo.getParentResourceNo().equals(resource.getResourceNo())) {
//                MenuVo menuVo = new MenuVo();
//                menuVo.setPath(resourceVo.getRequestPath());
//                menuVo.setName(resourceVo.getResourceName());
//                menuVo.setPath(resource.getRequestPath());
//                menuVo.setComponent(component + "/" + resourceVo.getRequestPath());
//
//                MenuMetaVo menuMetaVo = MenuMetaVo.builder()
//                        .icon(resourceVo.getIcon())
//                        .title(resourceVo.getResourceName())
//                        .build();
//                menuVo.setMeta(menuMetaVo);
//
//                menuVo.setRedirect("/" + resource.getResourceName() + "/" + resourceVo.getResourceName());
//
//                menuVo.setChildren(getChildrens(resourceVo, resources, resource.getRequestPath()));
//                childrenList.add(menuVo);
//            }
//        }
//
//        return childrenList;
//    }


    /**
     * 查询菜单使用数量
     *
     * @param resourceNo 菜单ID
     * @return 结果
     */
    public boolean checkMenuExistRole(String resourceNo) {
        int result = roleResourceMapper.checkMenuExistRole(resourceNo);
        return result > 0 ? true : false;
    }


    /**
     * 是否存在菜单子节点
     *
     * @param resourceNo 菜单ID
     * @return 结果
     */
    private boolean hasChildByMenuId(String resourceNo) {
        int result = resourceMapper.hasChildByMenuId(resourceNo);
        return result > 0 ? true : false;
    }

    /**
     * 创建资源编号
     *
     * @param parentResourceNo
     * @param isIgnore
     * @return
     */
    private String createResourceNo(String parentResourceNo, boolean isIgnore) {
        //100 001 000 000 000
        //100 001 001 000 000
        //100 001 001 001 000
        //100 001 001 001 001 001
        //判断资源编号是否大于三级
        if (isIgnore && NoProcessing.processString(parentResourceNo).length() / 3 >= 5) {
            throw new BaseException(BasicEnum.RESOURCE_DEPTH_UPPER_LIMIT);
        }
        //根据父资源编号查询子资源
        ResourceDto dto = ResourceDto.builder().parentResourceNo(parentResourceNo).build();
        List<Resource> resourceList = resourceMapper.selectList(dto);
        if (EmptyUtil.isNullOrEmpty(resourceList)) {
            //无下属节点，创建新的节点编号
            //100 001 001 001 000 -->100 001 001 001 001
            return NoProcessing.createNo(parentResourceNo, false);
        } else {
            //有下属节点，在已有节点上追加
            //100 001 001 001 000 -->100 001 001 001 003 -->100 001 001 001 004
            //先获取已有节点的最大值
            Long maxNo = resourceList.stream()
                    .map(resource -> {
                        return Long.valueOf(resource.getResourceNo());
                    }).max(Comparator.comparing(i -> i)).get();
            return NoProcessing.createNo(String.valueOf(maxNo), true);
        }

    }

}
